/**
 * Copyright (c) 2009 Blue Whale Systems Ltd
 * 
 * This software is provided "as is," and the copyright holder makes no representations or warranties, express or
 * implied, including but not limited to warranties of merchantability or fitness for any particular purpose or that the
 * use of this software or documentation will not infringe any third party patents, copyrights, trademarks or other
 * rights.
 * 
 * The copyright holder will not be liable for any direct, indirect special or consequential damages arising out of any
 * use of this software or documentation.
 */
package com.bluewhalesystems.client.lwuit.richtext;

import com.sun.lwuit.*;

public final class RichTextData
{
    public static final int DEFAULT_INITIAL_CAPACITY = 1024;

    /**
     * Reads an int from the buffer, i.e., two chars. Useful when the data is structured beyond a single char.
     * 
     * @param aBuffer buffer to read from
     * @param aOffset offset to read from
     * @return an int composed from the char at offset and the next one
     */
    public static int readInt( char[] aBuffer, int aOffset )
    {
        return aBuffer[aOffset + 1] | ( aBuffer[aOffset] << 0x10 );
    }

    /**
     * Writes an int to the buffer as two chars
     * 
     * @param aValue value to write
     * @param aBuffer buffer to append to
     */
    public static void writeInt( int aValue, RichTextData aRichTextData )
    {
        aRichTextData.iBuffer.append( (char) ( ( aValue & 0xFFFF0000 ) >>> 0x10 ) );
        aRichTextData.iBuffer.append( (char) ( aValue & 0x0000FFFF ) );
    }

    public void setFont( Font aFont )
    {
        iFont = aFont;
        iRowHeight = iFont.getHeight();

        iBuffer.append( RichTextArea.INSTRUCTION_SET_FONT );
        iBuffer.append( (char) ( iFont.getFace() | iFont.getSize() | iFont.getStyle() ) );
    }

    public void addTextAtCursor( String aString )
    {
        // Add a newline by default since otherwise it's too easy to not account for the last piece of text.
        addTextAtCursor( aString, true );
    }

    public void addTextAtCursor( String aString, boolean aAddNewline )
    {
        char[] chars = aString.toCharArray();
        iBuffer.append( aAddNewline ? RichTextArea.INSTRUCTION_DRAW_TEXT_LINE : RichTextArea.INSTRUCTION_DRAW_TEXT );
        iBuffer.append( (char) chars.length );
        iBuffer.append( (char) iFont.charsWidth( chars, 0, chars.length ) );
        iBuffer.append( chars, 0, chars.length );

        if( aAddNewline )
        {
            iHeight += iRowHeight + iRowGap;
        }
    }

    public void clearToNewline()
    {
        iBuffer.append( RichTextArea.INSTRUCTION_NEWLINE );
        iHeight += iRowHeight + iRowGap;
    }

    public void clearToNewline( char aXDelta )
    {
        iBuffer.append( RichTextArea.INSTRUCTION_NEWLINE_WITH_X );
        iBuffer.append( aXDelta );
        iHeight += iRowHeight + iRowGap;
    }

    public void setTextColor( int aColor )
    {
        iBuffer.append( RichTextArea.INSTRUCTION_SET_COLOR );
        writeInt( aColor, this );
    }

    public void moveCursor( char aXDelta, char aYDelta )
    {
        iBuffer.append( RichTextArea.INSTRUCTION_MOVE_XY );
        iBuffer.append( aXDelta );
        iBuffer.append( aYDelta );
    }

    public int getHeight()
    {
        return iHeight;
    }

    public GrowableCharArray getDataBuffer()
    {
        return iBuffer;
    }

    public void setRowGap( int aRowGap )
    {
        iRowGap = aRowGap;
    }

    public void embedObject( char aWidth, char aHeight, char aId )
    {
        iBuffer.append( RichTextArea.INSTRUCTION_DRAW_OBJECT );
        iBuffer.append( aWidth );
        iBuffer.append( aHeight );
        iBuffer.append( aId );
    }
    
    public RichTextData()
    {
        this( DEFAULT_INITIAL_CAPACITY );
    }

    public RichTextData( int aCapacity )
    {
        iBuffer = new GrowableCharArray( aCapacity );        

        // TODO: Once a model is used to create this, move this init functionality there.
        iBuffer.append( RichTextAreaModel.DATA_VERSION );
    }

    private GrowableCharArray iBuffer;
    private int               iHeight;
    private int               iRowHeight;
    private int               iRowGap;
    private Font              iFont;
}
